package com.authine.cloudpivot.ext.controller;

import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.engine.api.model.organization.UserModel;
import com.authine.cloudpivot.engine.api.model.runtime.BizObjectCreatedModel;
import com.authine.cloudpivot.engine.api.model.runtime.SelectionValue;
import com.authine.cloudpivot.engine.api.model.runtime.WorkflowInstanceModel;
import com.authine.cloudpivot.engine.enums.status.WorkflowInstanceStatus;
import com.authine.cloudpivot.engine.enums.type.BizObjectStatusType;
import com.authine.cloudpivot.ext.vo.oa.ShortMsgFlowVo;
import com.authine.cloudpivot.web.api.dubbo.DubboConfigService;
import com.authine.cloudpivot.web.api.utils.HttpClientUtils;
import com.authine.cloudpivot.web.api.view.ResponseResult;
import com.authine.cloudpivot.web.api.view.runtime.StartWorkflowDataVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 用户自定义发起流程
 */
@RestController
@RequestMapping("/api/cust/acl")
@Slf4j
public class QxAclController {

    @Value("${custom.aclAppsUrl:http://acl.test.beidoubw.com/notify/role/oa/app/list}")
    private String aclAppsUrl;
    @Value("${custom.aclRolesUrl:http://acl.test.beidoubw.com/notify/role/oa/role/list}")
    private String aclRolesUrl;
    @Value("${custom.aclRoleOptUrl:http://acl.test.beidoubw.com/notify/role/oa/member}")
    private String aclRoleOptUrl;
    @Value("${custom.aclRoleCanceUrl:http://acl.test.beidoubw.com/notify/role/oa/remove-member/cancel}")
    private String aclRoleCanceUrl;

    private final String shortMsgFlowCode = "appPermApplication";

    @Autowired
    private DubboConfigService dubboConfigService;
    @Autowired
    private CustmStartWorkflow custmStartWorkflow;


    @RequestMapping("/apps")
    public ResponseResult getAclApps (){

        ResponseResult rsp = ResponseResult.builder().errcode(-1l).errmsg("失败").build();

        try {
//            String rst = HttpClientUtils.doGet(aclAppsUrl, getHeaderMap("com.primeton.esb.producer.acl.apps"));
            String rst = HttpClientUtils.doGet(aclAppsUrl);

            if (rst != null) {
                JSONObject rstJson =   JSON.parseObject(rst);

                String code = rstJson.getString("code");

                if ("200".equals(code)){

                    rsp.setErrmsg("成功");
                    rsp.setErrcode(0l);
                    rsp.setData(rstJson.get("data"));
                }else{
                    rsp.setErrmsg(rst);
                }

            }

        } catch (Exception e) {
            log.info(e.getMessage(), e);
            rsp.setErrcode(-1l);
            rsp.setErrmsg("系统异常");
        }

        return rsp;
    }

    @RequestMapping("/roles")
    public ResponseResult getAclRoles (String appId){

        ResponseResult rsp = ResponseResult.builder().errcode(-1l).errmsg("失败").build();


        try {

            String url =  aclRolesUrl.concat("?appId=").concat(appId);
           // String rst = HttpClientUtils.doGet(url, getHeaderMap("com.primeton.esb.producer.acl.app.roles"));
            String rst = HttpClientUtils.doGet(url);

            if (rst != null) {
                JSONObject rstJson =   JSON.parseObject(rst);
                String code = rstJson.getString("code");
                if ("200".equals(code)){
                    rsp.setErrmsg("成功");
                    rsp.setErrcode(0l);
                    rsp.setData(rstJson.get("data"));
                }else{
                    rsp.setErrmsg(rst);
                }
            }

        } catch (Exception e) {
            log.info(e.getMessage(), e);
            rsp.setErrcode(-1l);
            rsp.setErrmsg("系统异常");
        }

        return rsp;
    }

    /**
     * 发起 短报文流程
     * targetType
     * applicant
     * opType
     * appName
     * appId
     * roleName
     * roleId
     * authorizerId
     * @return
     */
    @RequestMapping("startWorkFlow")
    public ResponseResult startWorkFlow (@RequestBody ShortMsgFlowVo smv) throws Exception {

     //   if (log.isDebugEnabled()) {
            log.info("ShortMsgFlowVo={}",smv);
     // }
        ResponseResult rst = validShortMsgFlowVo(smv);

        if (rst.getErrcode()!=0l){
            return  rst;
        }

        List<StartWorkflowDataVO> list = new ArrayList<>();


        String[] targetObjIdArray = smv.getTargetObjIds().split(",");


        if ("0".equals(smv.getTargetType())) {//用户

            list.addAll(getStartWorkFlowData(smv,targetObjIdArray)) ;

        }else{
            String[] targetObjNameArray = smv.getTargetObjNames().split(",");
            if (targetObjIdArray.length != targetObjNameArray.length) {
                rst.setErrcode(-1l);
                rst.setErrmsg(String.format("批量操作组id数量与组名称长度不一致,ids=%s,names=%s", targetObjIdArray.length,targetObjNameArray.length));
                return rst;
            }
            list.addAll(getStartWorkFlowData(smv, targetObjIdArray, targetObjNameArray)) ;
        }

        int suc=0;
        int err=0;
        for (StartWorkflowDataVO bizObject : list) {
            ResponseResult<String> result = custmStartWorkflow.startWorkflow(bizObject);

            if (result.getErrcode()==0l){
                suc++;
            }else{
                err++;
            }
        }

        rst.setErrcode(0l);
        rst.setErrmsg(String.format("批量操作,总流程数=%s,成功=%s,失败=%s",list.size(),suc,err ));

        return rst;
    }

    private List<StartWorkflowDataVO> getStartWorkFlowData(ShortMsgFlowVo smv,String [] userNmaes) throws Exception {
        List<StartWorkflowDataVO> list = new ArrayList<>();
        UserModel user ;
        Map<String, Object> data1 = getStartWorkFlowData(smv);

        data1.put("targetType", "用户");
        data1.put("targetTypeVal","0");

        Map<String,Object> data ;
        StartWorkflowDataVO bizObject ;

        for (int i = 0; i < userNmaes.length; i++) {
            user = dubboConfigService.getOrganizationFacade().getUserByUsername(userNmaes[i]);

            if (user == null) {
                throw new Exception(String.format("申请人[%s],账号在云枢里不存在", userNmaes[i]));
            }

            data =  new HashMap<>(data1);
            data.put("applicant", new Map[]{MapBuilder.create(new HashMap<String,Object>()).put("id",user.getId()).put("type",3).build()});


            bizObject = new StartWorkflowDataVO();

            bizObject.setWorkflowCode(shortMsgFlowCode);
            bizObject.setUsername(smv.getExecUserId());
            bizObject.setFinishStart(true);
            bizObject.setData(data);

            list.add(bizObject);
        }
        return list;
    }

    private List<StartWorkflowDataVO> getStartWorkFlowData(ShortMsgFlowVo smv,String [] groupIds,String[] groupNames){
        List<StartWorkflowDataVO> list = new ArrayList<>();

        Map<String, Object> data1 = getStartWorkFlowData(smv);
        data1.put("targetType", "组");
        data1.put("targetTypeVal","1");

        Map<String,Object> data ;
        StartWorkflowDataVO bizObject ;
        for (int i = 0; i < groupIds.length; i++) {
            data =  new HashMap<>(data1);
            data.put("targetGroupId",groupIds[i]);
            data.put("targetGroupName",groupNames[i]);
            bizObject = new StartWorkflowDataVO();

            bizObject.setWorkflowCode(shortMsgFlowCode);
            bizObject.setUsername(smv.getExecUserId());
            bizObject.setFinishStart(true);
            bizObject.setData(data);
            list.add(bizObject);
        }
        return list;
    }



    private Map<String,Object> getStartWorkFlowData(ShortMsgFlowVo smv){
        Map<String, Object> data = new HashMap<>();

        data.put("opType","1".equals(smv.getOpType())?"新增":"撤销");
        data.put("opTypeVal",smv.getOpType());
        data.put("applyDate",new Date());
        data.put("appName",smv.getAppName());
        data.put("appId",smv.getAppId());
        data.put("roleName",smv.getRoleName());
        data.put("roleId",smv.getRoleId());
        data.put("authorizerId",smv.getAuthorizerId());
        data.put("remark",smv.getReason());

        data.put("wfsource","1");//流程发起来源 acl

        UserModel user = dubboConfigService.getOrganizationFacade().getUserByUsername(smv.getAuthorizerId());
        if (user != null) {
            data.put("applyUser", new Map[]{MapBuilder.create(new HashMap<String,Object>()).put("id",user.getId()).put("type",3).build()});
        }

        return  data;
    }


    private ResponseResult validShortMsgFlowVo(ShortMsgFlowVo smv){
        ResponseResult.ResponseResultBuilder<Object> rst = ResponseResult.builder().errcode(0l);

        try {


            for (Field f : smv.getClass().getDeclaredFields()) {
                f.setAccessible(true);

                System.out.print(f.getName() + ":");
                System.out.println(f.get(smv));

                if ("0".equals(smv.getTargetType()) && "targetObjNames".equals(f.getName())){
                    continue;
                }

                if (f.get(smv) == null || StringUtils.isBlank(f.get(smv).toString())) {
                    return rst.errcode(-1l).errmsg(f.getName()+" is empty").build();
                }

            }
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        }



        return rst.build();
    }
    /**
     * acl 流程撤销 回调
     * @param id
     * @return
     */
    @RequestMapping("/shortMsgCancelCall")
    public ResponseResult shortMsgCancelCall(String id){
        return  aclCall(id,0,aclRoleCanceUrl);
    }

    /**
     * acl 流程完成 回调
     * @param id
     * @return
     */
    @RequestMapping("/shortMsgFlowCall")
    public ResponseResult shortMsgFlowCall(String id){
        return aclCall(id,1,aclRoleOptUrl);
    }

    /**
     * opt 1 compiled,0 Cancel
     * @return
     */
    private  ResponseResult aclCall(String id,int opt,String url){
        ResponseResult.ResponseResultBuilder<Object> builder = ResponseResult.builder();
        BizObjectCreatedModel bizObject = dubboConfigService.getBizObjectFacade().getBizObject(shortMsgFlowCode, id);

        log.info("aclCallUrl={}",url);

        if (bizObject == null) {
            return builder.errmsg("数据不存在").errcode(-1l).build();
        } else if (StringUtils.isBlank(bizObject.getWorkflowInstanceId())) {
            return builder.errmsg("流程不存在").errcode(-1l).build();
        }

        String wfsource = (String) bizObject.get("wfsource");

        if (opt == 0 && "0".equals(wfsource)) {
            log.info("流程作废,发起来源云枢,不调用回调,opt ={},wfsource={}}", opt,wfsource);
            return builder.errmsg(String.format("流程作废,发起来源云枢,不调用回调,opt =%s,wfsource=%s", opt,wfsource)).errcode(0l).build();
        }


        WorkflowInstanceModel workflowInstance = dubboConfigService.getWorkflowInstanceFacade().getWorkflowInstance(bizObject.getWorkflowInstanceId());

        final WorkflowInstanceStatus wfState = workflowInstance.getState();

        log.info("流程状态 state:{}",wfState.getName());

        // 操作类型 操作类型：1.添加 0.删除 , 当前流程作废,只有操作是 0删除时,调用 aclRoleCanceUrl 接口
        Integer opType = Integer.valueOf((String) bizObject.get("opTypeVal"));
        log.info("操作类型 opType:{}",opType);
        log.info("操作类型 opt:{}",opt);

        if ( opType == null) {
            return builder.errmsg("opType操作类型为空....").errcode(-1l).build();
        }else if (opt == 0 && opType.intValue() ==1){
            //当前流程作废,操作是 1.添加时,不做任何操作
            log.info("流程已作废,操作类型是添加,不调用回调,opt ={},opType={}", opt,opType);
            return builder.errmsg(String.format("流程已作废,操作类型是添加,不调用回调,opt =%s,opType=%s", opt,opType)).errcode(0l).build();
        }

        String oaProcessId = bizObject.getWorkflowInstanceId();
        Integer targetType = Integer.valueOf((String) bizObject.get("targetTypeVal"));
        Integer appId = Integer.valueOf((String) bizObject.get("appId"));
        Integer roleId =  Integer.valueOf((String) bizObject.get("roleId"));
        String sourceDesc = (String) bizObject.get("remark");
        Date applyDate = (Date) bizObject.get("applyDate");
        String targetUserId = "";
        String targetGroupId ="";
        if (targetType.intValue()==0){
            List<SelectionValue> applicantList = (List<SelectionValue>) bizObject.get("applicant");
            // log.info("applicant={},{}",applicantList.get(0).getClass(),applicantList);
            if (applicantList !=null && !applicantList.isEmpty()){
                UserModel user = dubboConfigService.getOrganizationFacade().getUser(applicantList.get(0).getId());
                if (user != null) {
                    targetUserId=user.getUsername();
                }
            }
        }else {
            targetGroupId = (String) bizObject.get("targetGroupId");
        }


        JSONObject data = new JSONObject();
        data.put("roleId", roleId);
        // 用户的域账号
        data.put("targetUserId", targetUserId);
        data.put("targetGroupId", targetGroupId);

        data.put("targetType", targetType);
        // 操作类型：1.添加 0.删除
        data.put("opType", opType);
        data.put("appId", appId);
        //流程号
        data.put("oaProcessId", oaProcessId);
        data.put("sourceDesc", sourceDesc);
        //Long型，生效时间(此处需要使用毫秒)
        data.put("validDate", applyDate.getTime());
        //Long型，失效时间（此处需要使用毫秒）
//        main.put("invalidDate", reason);

        log.info("data={}",data);
        try {

            String s = HttpClientUtils.doPost(url, JSON.toJSONString(data),
                    MapUtil.builder("Content-Type","application/json").build());
            log.info("rst={}", s);
            JSONObject rst = (JSONObject) JSONObject.parse(s);

            if ("200".equals(rst.get("code"))) {
                builder.errcode(0l).errmsg("成功");
            } else {
                builder.errcode(-1l).errmsg("失败").data(s);
            }
        } catch (Exception e) {
            log.info("系统异常",e);
            builder.errmsg("系统异常").errcode(-1l);
        }

        return builder.build();

    }


    private Map<String, String> getHeaderMap(String operationCode) {
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("Authorization", "Basic " + "YWRtaW5pc3RyYXRvcjpQQHNzd29yZDAx");
        headerMap.put("Content-Type", "application/json; charset=utf-8");
        headerMap.put("ClientId", "com.primeton.esb.consumer.oa");
        headerMap.put("OperationCode", operationCode);
        headerMap.put("Timestamp", String.valueOf(System.currentTimeMillis()));
        return headerMap;
    }




    /**
     * test
     * @return
     */
    @RequestMapping("testServerRule")
    public ResponseResult TestServerRule(String id){

        log.info("bizObjId ={}", id);
        ResponseResult.ResponseResultBuilder<Object> builder = ResponseResult.builder().errcode(-1l).errmsg("失败");



        BizObjectCreatedModel bizObject = dubboConfigService.getBizObjectFacade().getBizObject(shortMsgFlowCode, id);
        BizObjectStatusType status = bizObject.getStatus();

        log.info("数据状态 status = {}",status.getName());

        WorkflowInstanceModel workflowInstance = dubboConfigService.getWorkflowInstanceFacade().getWorkflowInstance(bizObject.getWorkflowInstanceId());
        WorkflowInstanceStatus state = workflowInstance.getState();

        log.info("流程状态 state = {}",state.getName());


        return builder.errcode(0l).errmsg(String.format("流程状态 state = %s ,数据状态 status = %s", state.getName(),status.getName())).build();
    }

}
